<!--
  组件：MemberSelectDialog
  描述：病区成员选择弹窗组件，支持搜索、勾选、确认与取消，保留与原页面100%兼容的交互。
  Props：
    - modelValue(Boolean)：弹窗显示/隐藏（v-model）
    - title(String)：弹窗标题，默认“选择病区成员”
    - loading(Boolean)：成员列表加载中状态
    - members(Array)：成员列表数据（由父组件提供）
    - initialSelected(Array)：初始已选成员列表（由父组件提供）
  Emits：
    - update:modelValue(Boolean)：用于关闭弹窗
    - confirm(Array)：确认选择，返回选中的成员列表
    - cancel()：取消选择
    - selected-change(Array)：当选择列表变化时触发
    - search(String)：输入搜索关键字时触发（父组件可选择远程搜索）
  Slots：
    - header：自定义头部区域
    - footer：自定义底部区域（默认提供“取消 / 确定”按钮）
    - item-extra：成员行右侧扩展区域（例如展示角色、标签等）
-->
<template>
  <el-dialog
    v-model="innerVisible"
    :title="title"
    width="600px"
    :close-on-click-modal="false"
    class="member-select-dialog"
  >
    <div class="dialog-content">
      <!-- 搜索框 -->
      <div class="search-section">
        <el-input
          v-model="keyword"
          placeholder="输入姓名快速查找"
          prefix-icon="Search"
          clearable
          @input="onSearch"
          class="search-input"
        />
      </div>

      <!-- 成员列表 -->
      <div class="member-list-section">
        <div class="list-header">
          <span class="selected-info">已选 {{ tempSelected.length }} 项</span>
        </div>
        <div class="member-list" v-loading="loading">
          <!-- 中文注释：使用过渡包裹列表与空状态，提供平滑显隐动画 -->
          <transition name="fade">
            <!-- 中文注释：当有匹配成员时，渲染成员列表 -->
            <div v-if="filteredMembers.length > 0" key="list">
              <div
                v-for="member in filteredMembers"
                :key="member.userId"
                class="member-list-item"
                :class="{ selected: tempSelected.some(m => m.userId === member.userId) }"
                @click="toggleMember(member)"
              >
                <el-checkbox
                  :model-value="tempSelected.some(m => m.userId === member.userId)"
                  @change="toggleMember(member)"
                  class="member-checkbox"
                />
                <div class="member-item-info">
                  <div class="member-item-name">{{ member.nickName }}</div>
                  <div class="member-item-details">{{ member.dept?.deptName }} · {{ member.phonenumber }}</div>
                </div>
                <!-- 可选扩展槽：在成员右侧追加内容 -->
                <slot name="item-extra" :member="member" />
              </div>
            </div>
            <!-- 中文注释：当搜索无匹配结果时，展示符合设计语言的空状态 -->
            <div v-else key="empty" class="empty-state">
              <!-- 中文注释：Element Plus 的 Empty 组件，保持与项目配色一致 -->
              <el-empty :image-size="80" description="未找到匹配结果">
                <!-- 中文注释：补充提示，引导用户调整搜索条件 -->
                <div class="empty-hint">请尝试调整搜索条件或清空关键字</div>
              </el-empty>
            </div>
          </transition>
        </div>
      </div>
    </div>

    <template #footer>
      <slot name="footer">
        <div class="dialog-footer">
          <el-button @click="handleCancel">取消</el-button>
          <el-button type="primary" @click="handleConfirm"> 确定 </el-button>
        </div>
      </slot>
    </template>
  </el-dialog>
</template>

<script setup>
// 中文注释：该组件使用局部状态管理临时选择列表与搜索关键字，并向父组件回传结果
import { ref, watch, computed } from 'vue'

// Props定义：包含弹窗可见性、标题、加载态、成员列表、初始选择
const props = defineProps({
  modelValue: { type: Boolean, default: false },
  title: { type: String, default: '选择病区成员' },
  loading: { type: Boolean, default: false },
  members: { type: Array, default: () => [] },
  initialSelected: { type: Array, default: () => [] }
})

// Emits定义：回传更新与操作事件
const emit = defineEmits(['update:modelValue', 'confirm', 'cancel', 'selected-change', 'search'])

// 内部可见性：与父组件双向绑定
const innerVisible = ref(props.modelValue)
watch(
  () => props.modelValue,
  v => {
    innerVisible.value = v
    // 打开弹窗时重置临时选择为初始选择
    if (v) {
      tempSelected.value = [...props.initialSelected]
      keyword.value = ''
      // 中文注释：重置后重新计算过滤列表
      filteredMembers.value = [...props.members]
    }
  }
)
watch(innerVisible, v => emit('update:modelValue', v))

// 搜索关键字与过滤列表
const keyword = ref('')
const filteredMembers = ref([...props.members])
watch(
  () => props.members,
  list => {
    // 中文注释：成员列表更新时，同步到过滤列表
    filteredMembers.value = [...list]
  }
)

// 临时选择列表：避免直接修改父组件数据
const tempSelected = ref([...props.initialSelected])

// 方法：搜索成员
const onSearch = () => {
  const k = keyword.value.trim()
  // 中文注释：本地过滤，父组件如需远程搜索可监听 search 事件
  emit('search', k)
  if (!k) {
    filteredMembers.value = [...props.members]
    return
  }
  filteredMembers.value = props.members.filter(
    m =>
      String(m.name || '').includes(k) || String(m.department || '').includes(k) || String(m.position || '').includes(k)
  )
}

// 方法：切换选择成员
const toggleMember = member => {
  const idx = tempSelected.value.findIndex(m => m.userId === member.userId)
  if (idx > -1) {
    tempSelected.value.splice(idx, 1)
  } else {
    tempSelected.value.push(member)
  }
  emit('selected-change', [...tempSelected.value])
}

// 方法：确认与取消
const handleConfirm = () => {
  emit('confirm', [...tempSelected.value])
  innerVisible.value = false
}
const handleCancel = () => {
  // 中文注释：取消时恢复初始选择并关闭
  tempSelected.value = [...props.initialSelected]
  innerVisible.value = false
  emit('cancel')
}
</script>
<style lang="scss" scoped>
.member-select-dialog {
  .dialog-content {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .search-section {
    .search-input {
      width: 100%;
    }
  }

  .member-list-section {
    .list-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 12px;
      color: var(--el-text-color-secondary);
      margin-bottom: 12px;
    }

    .member-list {
      /* 中文注释：固定响应式高度，确保有值/无值时容器高度一致，避免视觉抖动 */
      height: clamp(240px, 40vh, 360px);
      overflow: auto;
      border: 1px solid var(--el-border-color);
      border-radius: 6px;
      padding: 6px;
      .member-list-item {
        display: flex;
        align-items: center;
        padding: 8px;
        border-radius: 6px;
        cursor: pointer;

        &:hover {
          background-color: var(--el-fill-color-light);
        }

        &.selected {
          background-color: var(--el-color-primary-light-9);
        }

        .member-checkbox {
          margin-right: 8px;
        }

        .member-item-info {
          display: flex;
          flex-direction: column;
          gap: 2px;

          .member-item-name {
            font-weight: 600;
          }
          .member-item-details {
            font-size: 12px;
            color: var(--el-text-color-secondary);
          }
        }
      }

      /* 中文注释：空状态容器——响应式居中、留白与配色保持一致 */
      .empty-state {
        display: flex;
        align-items: center;
        justify-content: center;
        height: 100%;
        text-align: center;

        /* 中文注释：深化描述文字颜色以保持与整体风格一致 */
        :deep(.el-empty__description) {
          color: var(--el-text-color-secondary);
        }

        .empty-hint {
          margin-top: 6px;
          font-size: 12px;
          color: var(--el-text-color-secondary);
        }
      }
    }
  }

  .dialog-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
  }
}

/* 中文注释：淡入淡出过渡动画，提升状态切换的平滑度 */
.fade-enter-active,
.fade-leave-active {
  transition:
    opacity 0.2s ease,
    transform 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
  transform: translateY(4px);
}
</style>
